home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_kernel_source / KERNEL / PRINTK.C < prev    next >
C/C++ Source or Header  |  1999-09-17  |  10KB  |  436 lines

  1. /*
  2.  *  linux/kernel/printk.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  *
  6.  * Modified to make sys_syslog() more flexible: added commands to
  7.  * return the last 4k of kernel messages, regardless of whether
  8.  * they've been read or not.  Added option to suppress kernel printk's
  9.  * to the console.  Added hook for sending the console messages
  10.  * elsewhere, in preparation for a serial line console (someday).
  11.  * Ted Ts'o, 2/11/93.
  12.  * Modified for sysctl support, 1/8/97, Chris Horn.
  13.  */
  14.  
  15. #include <linux/mm.h>
  16. #include <linux/tty_driver.h>
  17. #include <linux/smp_lock.h>
  18. #include <linux/console.h>
  19. #include <linux/init.h>
  20.  
  21. #include <asm/uaccess.h>
  22.  
  23. #define LOG_BUF_LEN    (16384)
  24.  
  25. static char buf[1024];
  26.  
  27. /* printk's without a loglevel use this.. */
  28. #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
  29.  
  30. /* We show everything that is MORE important than this.. */
  31. #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
  32. #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
  33.  
  34. unsigned long log_size = 0;
  35. struct wait_queue * log_wait = NULL;
  36.  
  37. /* Keep together for sysctl support */
  38. int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
  39. int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL;
  40. int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
  41. int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
  42.  
  43. struct console *console_drivers = NULL;
  44. static char log_buf[LOG_BUF_LEN];
  45. static unsigned long log_start = 0;
  46. static unsigned long logged_chars = 0;
  47. struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
  48. static int preferred_console = -1;
  49.  
  50. /*
  51.  *    Setup a list of consoles. Called from init/main.c
  52.  */
  53. void __init console_setup(char *str, int *ints)
  54. {
  55.     struct console_cmdline *c;
  56.     char name[sizeof(c->name)];
  57.     char *s, *options;
  58.     int i, idx;
  59.  
  60.     /*
  61.      *    Decode str into name, index, options.
  62.      */
  63.     if (str[0] >= '0' && str[0] <= '9') {
  64.         strcpy(name, "ttyS");
  65.         strncpy(name + 4, str, sizeof(name) - 5);
  66.     } else
  67.         strncpy(name, str, sizeof(name) - 1);
  68.     name[sizeof(name) - 1] = 0;
  69.     if ((options = strchr(str, ',')) != NULL)
  70.         *(options++) = 0;
  71. #ifdef __sparc__
  72.     if (!strcmp(str, "ttya"))
  73.         strcpy(name, "ttyS0");
  74.     if (!strcmp(str, "ttyb"))
  75.         strcpy(name, "ttyS1");
  76. #endif
  77.     for(s = name; *s; s++)
  78.         if (*s >= '0' && *s <= '9')
  79.             break;
  80.     idx = simple_strtoul(s, NULL, 10);
  81.     *s = 0;
  82.  
  83.     /*
  84.      *    See if this tty is not yet registered, and
  85.      *    if we have a slot free.
  86.      */
  87.     for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
  88.         if (strcmp(console_cmdline[i].name, name) == 0 &&
  89.               console_cmdline[i].index == idx) {
  90.                 preferred_console = i;
  91.                 return;
  92.         }
  93.     if (i == MAX_CMDLINECONSOLES)
  94.         return;
  95.     preferred_console = i;
  96.     c = &console_cmdline[i];
  97.     memcpy(c->name, name, sizeof(c->name));
  98.     c->options = options;
  99.     c->index = idx;
  100. }
  101.  
  102.  
  103. /*
  104.  * Commands to do_syslog:
  105.  *
  106.  *     0 -- Close the log.  Currently a NOP.
  107.  *     1 -- Open the log. Currently a NOP.
  108.  *     2 -- Read from the log.
  109.  *     3 -- Read up to the last 4k of messages in the ring buffer.
  110.  *     4 -- Read and clear last 4k of messages in the ring buffer
  111.  *     5 -- Clear ring buffer.
  112.  *     6 -- Disable printk's to console
  113.  *     7 -- Enable printk's to console
  114.  *    8 -- Set level of messages printed to console
  115.  */
  116. int do_syslog(int type, char * buf, int len)
  117. {
  118.     unsigned long i, j, count, flags;
  119.     int do_clear = 0;
  120.     char c;
  121.     int error = -EPERM;
  122.  
  123.     lock_kernel();
  124.     error = 0;
  125.     switch (type) {
  126.     case 0:        /* Close log */
  127.         break;
  128.     case 1:        /* Open log */
  129.         break;
  130.     case 2:        /* Read from log */
  131.         error = -EINVAL;
  132.         if (!buf || len < 0)
  133.             goto out;
  134.         error = 0;
  135.         if (!len)
  136.             goto out;
  137.         error = verify_area(VERIFY_WRITE,buf,len);
  138.         if (error)
  139.             goto out;
  140.         error = wait_event_interruptible(log_wait, log_size);
  141.         if (error)
  142.             goto out;
  143.         i = 0;
  144.         while (log_size && i < len) {
  145.             c = *((char *) log_buf+log_start);
  146.             log_start++;
  147.             log_size--;
  148.             log_start &= LOG_BUF_LEN-1;
  149.             sti();
  150.             __put_user(c,buf);
  151.             buf++;
  152.             i++;
  153.             cli();
  154.         }
  155.         sti();
  156.         error = i;
  157.         break;
  158.     case 4:        /* Read/clear last kernel messages */
  159.         do_clear = 1; 
  160.         /* FALL THRU */
  161.     case 3:        /* Read last kernel messages */
  162.         error = -EINVAL;
  163.         if (!buf || len < 0)
  164.             goto out;
  165.         error = 0;
  166.         if (!len)
  167.             goto out;
  168.         error = verify_area(VERIFY_WRITE,buf,len);
  169.         if (error)
  170.             goto out;
  171.         /*
  172.          * The logged_chars, log_start, and log_size values may
  173.          * change from an interrupt, so we disable interrupts.
  174.          */
  175.         __save_flags(flags);
  176.         __cli();
  177.         count = len;
  178.         if (count > LOG_BUF_LEN)
  179.             count = LOG_BUF_LEN;
  180.         if (count > logged_chars)
  181.             count = logged_chars;
  182.         j = log_start + log_size - count;
  183.         __restore_flags(flags);
  184.         for (i = 0; i < count; i++) {
  185.             c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
  186.             __put_user(c, buf++);
  187.         }
  188.         if (do_clear)
  189.             logged_chars = 0;
  190.         error = i;
  191.         break;
  192.     case 5:        /* Clear ring buffer */
  193.         logged_chars = 0;
  194.         break;
  195.     case 6:        /* Disable logging to console */
  196.         console_loglevel = minimum_console_loglevel;
  197.         break;
  198.     case 7:        /* Enable logging to console */
  199.         console_loglevel = default_console_loglevel;
  200.         break;
  201.     case 8:
  202.         error = -EINVAL;
  203.         if (len < 1 || len > 8)
  204.             goto out;
  205.         if (len < minimum_console_loglevel)
  206.             len = minimum_console_loglevel;
  207.         console_loglevel = len;
  208.         error = 0;
  209.         break;
  210.     default:
  211.         error = -EINVAL;
  212.         break;
  213.     }
  214. out:
  215.     unlock_kernel();
  216.     return error;
  217. }
  218.  
  219. asmlinkage int sys_syslog(int type, char * buf, int len)
  220. {
  221.     if ((type != 3) && !capable(CAP_SYS_ADMIN))
  222.         return -EPERM;
  223.     return do_syslog(type, buf, len);
  224. }
  225.  
  226.  
  227. spinlock_t console_lock;
  228.  
  229. asmlinkage int printk(const char *fmt, ...)
  230. {
  231.     va_list args;
  232.     int i;
  233.     char *msg, *p, *buf_end;
  234.     int line_feed;
  235.     static signed char msg_level = -1;
  236.     long flags;
  237.  
  238.     spin_lock_irqsave(&console_lock, flags);
  239.     va_start(args, fmt);
  240.     i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
  241.     buf_end = buf + 3 + i;
  242.     va_end(args);
  243.     for (p = buf + 3; p < buf_end; p++) {
  244.         msg = p;
  245.         if (msg_level < 0) {
  246.             if (
  247.                 p[0] != '<' ||
  248.                 p[1] < '0' || 
  249.                 p[1] > '7' ||
  250.                 p[2] != '>'
  251.             ) {
  252.                 p -= 3;
  253.                 p[0] = '<';
  254.                 p[1] = default_message_loglevel + '0';
  255.                 p[2] = '>';
  256.             } else
  257.                 msg += 3;
  258.             msg_level = p[1] - '0';
  259.         }
  260.         line_feed = 0;
  261.         for (; p < buf_end; p++) {
  262.             log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = *p;
  263.             if (log_size < LOG_BUF_LEN)
  264.                 log_size++;
  265.             else {
  266.                 log_start++;
  267.                 log_start &= LOG_BUF_LEN-1;
  268.             }
  269.             logged_chars++;
  270.             if (*p == '\n') {
  271.                 line_feed = 1;
  272.                 break;
  273.             }
  274.         }
  275.         if (msg_level < console_loglevel && console_drivers) {
  276.             struct console *c = console_drivers;
  277.             while(c) {
  278.                 if ((c->flags & CON_ENABLED) && c->write)
  279.                     c->write(c, msg, p - msg + line_feed);
  280.                 c = c->next;
  281.             }
  282.         }
  283.         if (line_feed)
  284.             msg_level = -1;
  285.     }
  286.     spin_unlock_irqrestore(&console_lock, flags);
  287.     wake_up_interruptible(&log_wait);
  288.     return i;
  289. }
  290.  
  291. void console_print(const char *s)
  292. {
  293.     struct console *c = console_drivers;
  294.     int len = strlen(s);
  295.  
  296.     while(c) {
  297.         if ((c->flags & CON_ENABLED) && c->write)
  298.             c->write(c, s, len);
  299.         c = c->next;
  300.     }
  301. }
  302.  
  303. void unblank_console(void)
  304. {
  305.     struct console *c = console_drivers;
  306.     while(c) {
  307.         if ((c->flags & CON_ENABLED) && c->unblank)
  308.             c->unblank();
  309.         c = c->next;
  310.     }
  311. }
  312.  
  313. /*
  314.  * The console driver calls this routine during kernel initialization
  315.  * to register the console printing procedure with printk() and to
  316.  * print any messages that were printed by the kernel before the
  317.  * console driver was initialized.
  318.  */
  319. void register_console(struct console * console)
  320. {
  321.     int    i,j,len;
  322.     int    p = log_start;
  323.     char    buf[16];
  324.     signed char msg_level = -1;
  325.     char    *q;
  326.  
  327.     /*
  328.      *    See if we want to use this console driver. If we
  329.      *    didn't select a console we take the first one
  330.      *    that registers here.
  331.      */
  332.     if (preferred_console < 0) {
  333.         if (console->index < 0)
  334.             console->index = 0;
  335.         if (console->setup == NULL ||
  336.             console->setup(console, NULL) == 0) {
  337.             console->flags |= CON_ENABLED | CON_CONSDEV;
  338.             preferred_console = 0;
  339.         }
  340.     }
  341.  
  342.     /*
  343.      *    See if this console matches one we selected on
  344.      *    the command line.
  345.      */
  346.     for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) {
  347.         if (strcmp(console_cmdline[i].name, console->name) != 0)
  348.             continue;
  349.         if (console->index >= 0 &&
  350.             console->index != console_cmdline[i].index)
  351.             continue;
  352.         if (console->index < 0)
  353.             console->index = console_cmdline[i].index;
  354.         if (console->setup &&
  355.             console->setup(console, console_cmdline[i].options) != 0)
  356.             break;
  357.         console->flags |= CON_ENABLED;
  358.         console->index = console_cmdline[i].index;
  359.         if (i == preferred_console)
  360.             console->flags |= CON_CONSDEV;
  361.         break;
  362.     }
  363.  
  364.     if (!(console->flags & CON_ENABLED))
  365.         return;
  366.  
  367.     /*
  368.      *    Put this console in the list - keep the
  369.      *    preferred driver at the head of the list.
  370.      */
  371.     if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
  372.         console->next = console_drivers;
  373.         console_drivers = console;
  374.     } else {
  375.         console->next = console_drivers->next;
  376.         console_drivers->next = console;
  377.     }
  378.     if ((console->flags & CON_PRINTBUFFER) == 0) return;
  379.  
  380.     /*
  381.      *    Print out buffered log messages.
  382.      */
  383.     for (i=0,j=0; i < log_size; i++) {
  384.         buf[j++] = log_buf[p];
  385.         p++; p &= LOG_BUF_LEN-1;
  386.         if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1)
  387.             continue;
  388.         buf[j] = 0;
  389.         q = buf;
  390.         len = j;
  391.         if (msg_level < 0) {
  392.             msg_level = buf[1] - '0';
  393.             q = buf + 3;
  394.             len -= 3;
  395.         }
  396.         if (msg_level < console_loglevel)
  397.             console->write(console, q, len);
  398.         if (buf[j-1] == '\n')
  399.             msg_level = -1;
  400.         j = 0;
  401.     }
  402. }
  403.  
  404.  
  405. int unregister_console(struct console * console)
  406. {
  407.         struct console *a,*b;
  408.     
  409.     if (console_drivers == console) {
  410.         console_drivers=console->next;
  411.         return (0);
  412.     }
  413.     for (a=console_drivers->next, b=console_drivers ;
  414.          a; b=a, a=b->next) {
  415.         if (a == console) {
  416.             b->next = a->next;
  417.             return 0;
  418.         }  
  419.     }
  420.     
  421.     return (1);
  422. }
  423.     
  424. /*
  425.  * Write a message to a certain tty, not just the console. This is used for
  426.  * messages that need to be redirected to a specific tty.
  427.  * We don't put it into the syslog queue right now maybe in the future if
  428.  * really needed.
  429.  */
  430. void tty_write_message(struct tty_struct *tty, char *msg)
  431. {
  432.     if (tty && tty->driver.write)
  433.         tty->driver.write(tty, 0, msg, strlen(msg));
  434.     return;
  435. }
  436.